﻿
#pragma once

#include <typeinfo>
#include <stdint.h>
#include <string>
#include <vector>

namespace tools
{
    struct ONLY_REGISTRED_TYPES;

    namespace wrapper_details{
    //-----------------------------------------------------------------------------------------
        enum eTYPE
        {
            eNOT_REGISTRED,
            eNULL,
            eBOOL,
            eI8, eI16, eI32, eI64, eU8, eU16, eU32, eU64,
            eF32, eF64,
            eSTRING, eWSTRING,
            eBYTE, eBLOB
        };
    //-----------------------------------------------------------------------------------------

    #define REGISTER_THIS_TYPE(type_name, enum_value, string_name) \
        template <>struct Enum2Type<enum_value>{ enum { eTYPE = enum_value }; typedef type_name Type; };\
        template <>struct Type2Enum<type_name> { enum { eTYPE = enum_value }; typedef type_name Type; };\
        template <>struct Enum2String<enum_value>{ static const char* Name() { return #string_name; } };

        template <size_t N>struct Enum2Type   { enum { eTYPE = eNOT_REGISTRED }; typedef void Type; };
        template <class T> struct Type2Enum   { enum { eTYPE = eNOT_REGISTRED }; typedef void Type; };
        template <size_t N>struct Enum2String { static const char* Name() { return typeid( typename Enum2Type<N>::Type ).name(); } };

        template <class T, size_t REGISTRED = Type2Enum<T>::eTYPE >struct Type2String 
        { 
            static const char* Name() { return Enum2String<REGISTRED>::Name(); }
        };
        template <class T>struct Type2String<T,0>
        { 
            static const char* Name() { return typeid(T).name(); }
        };


        typedef char Byte;

        REGISTER_THIS_TYPE( bool,                 eBOOL,      BOOL    );
        REGISTER_THIS_TYPE( int8_t,               eI8 ,       INT8    );
        REGISTER_THIS_TYPE( int16_t,              eI16,       INT16   );
        REGISTER_THIS_TYPE( int32_t,              eI32,       INT32   );
        REGISTER_THIS_TYPE( int64_t,              eI64,       INT64   );
        REGISTER_THIS_TYPE( uint8_t,              eU8 ,       UINT8   );
        REGISTER_THIS_TYPE( uint16_t,             eU16,       UINT16  );
        REGISTER_THIS_TYPE( uint32_t,             eU32,       UINT32  );
        REGISTER_THIS_TYPE( uint64_t,             eU64,       UINT64  );
        REGISTER_THIS_TYPE( float,                eF32,       FLOAT32 );
        REGISTER_THIS_TYPE( double,               eF64,       FLOAT64 );
        REGISTER_THIS_TYPE( Byte,                 eBYTE,      BYTE    );
        REGISTER_THIS_TYPE( ::std::string,        eSTRING,    STRING  );
        REGISTER_THIS_TYPE( ::std::wstring,       eWSTRING,   WSTRING );
        REGISTER_THIS_TYPE( ::std::vector<Byte>,  eBLOB,      BLOB    );
        #undef REGISTER_THIS_TYPE

        static_assert(sizeof(float)  == 4, "Bad type size.");
        static_assert(sizeof(double) == 8, "Bad type size.");

    }//namespace wrapper_details

}//namespace tools

